home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / MacApp Release 10 / MacApp Release 10 - HD Ready / Libraries / Core / Sources / USegments.cp < prev    next >
Encoding:
Text File  |  1996-04-03  |  32.2 KB  |  1,143 lines  |  [TEXT/MPS ]

  1. //----------------------------------------------------------------------------------------
  2. // USegments.cp
  3. // Copyright © 1995-96 by Apple Computer, Inc. All rights reserved.
  4. //----------------------------------------------------------------------------------------
  5.  
  6. #ifndef __USEGMENTS__
  7. #include "USegments.h"
  8. #endif
  9.  
  10. #if qSegments
  11.  
  12. // MacApp
  13.  
  14. #ifndef __UDEBUG__
  15. #include "UDebug.h"
  16. #endif
  17.  
  18. #ifndef __UFAILURE__
  19. #include "UFailure.h"
  20. #endif
  21.  
  22. #ifndef __UCOREUTILITIES__
  23. #include "UCoreUtilities.h"
  24. #endif
  25.  
  26. #ifndef __UMEMORY__
  27. #include "UMemory.h"
  28. #endif
  29.  
  30. #ifndef __UNIVERSALSTARTUP__
  31. #include "UniversalStartup.h"
  32. #endif
  33.  
  34. #ifndef __UPATCH__
  35. #include "UPatch.h"
  36. #endif
  37.  
  38. // OpenDoc
  39.  
  40. #ifndef _MEMMGR_
  41. #include "MemMgr.h"
  42. #endif
  43.  
  44. // Toolbox
  45.  
  46. #ifndef __ERRORS__
  47. #include <Errors.h>
  48. #endif
  49.  
  50. #ifndef __LOWMEM__
  51. #include <LowMem.h>
  52. #endif
  53.  
  54. #ifndef __MEMORY__
  55. #include <Memory.h>
  56. #endif
  57.  
  58. #ifndef __RESOURCES__
  59. #include <Resources.h>
  60. #endif
  61.  
  62. #if (qModelFarCode || qModelCFM) && !defined(__MWERKS__)
  63. #define qUseRTLib    TRUE
  64. #else
  65. #define qUseRTLib    FALSE
  66. #endif
  67.  
  68. #if qUseRTLib
  69.     #ifndef __RTLIB__
  70.     #include "RtLib.h"
  71.     #endif
  72. #endif
  73.  
  74. #ifndef __SEGLOAD__
  75. #include <SegLoad.h>
  76. #endif
  77.  
  78. #ifndef __TRAPS__
  79. #include <Traps.h>
  80. #endif
  81.  
  82. // ANSI
  83.  
  84. #ifndef __LIMITS__
  85. #include <limits.h>
  86. #endif
  87.  
  88. #if qDebugMsg
  89.     #ifndef __STDIO__
  90.     #include <stdio.h>
  91.     #endif
  92. #endif
  93.  
  94. //----------------------------------------------------------------------------------------
  95. // CLASS CCodeSegmentGrowZoneHook
  96. //----------------------------------------------------------------------------------------
  97.  
  98. class CCodeSegmentGrowZoneHook : public CGrowZoneHook
  99. {
  100.   public:
  101.     CCodeSegmentGrowZoneHook();
  102.     virtual ~CCodeSegmentGrowZoneHook();
  103.  
  104.     virtual Size TotalSize(Boolean justLocked);
  105.         // Returns the total number of bytes of the code segments currently in RAM
  106.         // (or only locked segments if justLocked is true). 
  107.  
  108.     virtual Size Purge(Size needed);
  109.         // Make memory available by emptying code segment handles. Returns the actual
  110.         // amount of memory purged. 
  111. };
  112.  
  113. //----------------------------------------------------------------------------------------
  114. // Constants
  115. //----------------------------------------------------------------------------------------
  116.  
  117. const short kHeapOverhead = 8;
  118.  
  119. //----------------------------------------------------------------------------------------
  120. // Globals to this module and externally available.
  121. //----------------------------------------------------------------------------------------
  122.  
  123. CCodeSegment* gCodeSegs;                        // includes seg 0 which is unused.
  124. Boolean gUnloadAllSegs = TRUE;
  125. short pMaxSegNum;                                // has extern
  126.  
  127. #if !qModelCFM
  128. TrapPatch pSegLoadPatch;                        // has extern
  129. #endif
  130.  
  131. short pOldResFile;                                // has extern
  132.  
  133. Boolean pLoadSegCalledFromOwnApp;                // has extern
  134.  
  135. // local private globals
  136. #if qUseRTLib
  137. static SegLoadHdlrPtr oldPreLoadHandler;
  138. static SegLoadHdlrPtr oldPostLoadHandler;
  139. #endif
  140.  
  141. // LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls LoadMacAppSegment.
  142. // ALoadMacAppSeg can only be referenced as a procedure pointer, because no args are
  143. // declared
  144.  
  145. #if qUseRTLib
  146. typedef pascal short(* HandlerType)(RTState* state);
  147. #endif
  148.  
  149. // Memory hook for our unit
  150. CCodeSegmentGrowZoneHook gCodeSegmentGrowZoneHook;
  151.  
  152. #if qDebug
  153. unsigned long CCodeSegment::gHighWater;
  154. #endif
  155.  
  156. //========================================================================================
  157. // EXTERNAL Procedures
  158. //========================================================================================
  159.  
  160. #if defined(__MWERKS__)
  161. extern pascal Boolean PreloadSegment(short theSegNum);
  162.     // In UMemory.More.CW.cp
  163. #endif
  164.  
  165. extern pascal void ALoadMacAppSeg();
  166.     // Function prototype for the routine in UMemory.a
  167.  
  168. //========================================================================================
  169. // GLOBAL Procedures
  170. //========================================================================================
  171.  
  172. extern pascal void PostLoadMacAppSegment();            // referenced by UMemory.a
  173.  
  174. static void DoInitUSegments(Size& sizeTempReserve);
  175.  
  176. static void CheckCallChain(const CStackFrame& frame,
  177.                            void* /* yourDataPtr */ );
  178.  
  179. static CCodeSegment* GetCodeSegmentFromName(const CStr255& name);
  180.  
  181. //----------------------------------------------------------------------------------------
  182. // GetCodeSegmentFromID: 
  183. //----------------------------------------------------------------------------------------
  184.  
  185. static inline CCodeSegment* GetCodeSegmentFromID(short segNumber)
  186. {
  187.     return gCodeSegs + segNumber;
  188. }
  189.  
  190. //----------------------------------------------------------------------------------------
  191. // InlineIsHandlePurged: 
  192. //----------------------------------------------------------------------------------------
  193.  
  194. static inline Boolean InlineIsHandlePurged(Handle h)
  195.     // don't use IsHandlePurged, it may be in an unloaded segment
  196. {
  197.     return *h == NULL;
  198. }
  199.  
  200. //----------------------------------------------------------------------------------------
  201. // InlineIsHandleEligible: 
  202. //----------------------------------------------------------------------------------------
  203. #pragma segment Main
  204.  
  205. static inline Boolean InlineIsHandleEligible(Handle h)
  206. {
  207.     // SRF rewrote as single expression and only used documented approved
  208.     // interface for GZSaveHnd
  209.     return h && (*h != NULL) && (h != GZSaveHnd());
  210. }
  211.  
  212. //========================================================================================
  213. // CLASS CCodeSegmentGrowZoneHook
  214. //========================================================================================
  215.  
  216. //----------------------------------------------------------------------------------------
  217. // CCodeSegmentGrowZoneHook constructor: 
  218. //----------------------------------------------------------------------------------------
  219. #pragma segment MAMiniInit
  220.  
  221. CCodeSegmentGrowZoneHook::CCodeSegmentGrowZoneHook()
  222. {
  223. }
  224.  
  225. //----------------------------------------------------------------------------------------
  226. // CCodeSegmentGrowZoneHook destructor: 
  227. //----------------------------------------------------------------------------------------
  228. #pragma segment MAMiniInit
  229.  
  230. CCodeSegmentGrowZoneHook::~CCodeSegmentGrowZoneHook()
  231. {
  232. }
  233.  
  234. //----------------------------------------------------------------------------------------
  235. // CCodeSegmentGrowZoneHook::TotalSize: 
  236. //----------------------------------------------------------------------------------------
  237. #pragma segment MAMemoryRes
  238.  
  239. Size CCodeSegmentGrowZoneHook::TotalSize(Boolean justLocked)
  240. {
  241.     Size total = 0;
  242.     for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  243.     {
  244.         Handle h = codeSegment->fCodeSeg;
  245.         if (h && !InlineIsHandlePurged(h))            // in memory already
  246.         {
  247.             //HNoPurge(h);
  248.             if (!justLocked || IsHandleLocked(h))
  249.                 total += codeSegment->GetSize() + kHeapOverhead;
  250.         }
  251.     }
  252.     return total;
  253. } // CCodeSegmentGrowZoneHook::TotalSize
  254.  
  255. //----------------------------------------------------------------------------------------
  256. // CCodeSegmentGrowZoneHook::Purge: 
  257. //----------------------------------------------------------------------------------------
  258. #pragma segment MAMemoryRes
  259.  
  260. Size CCodeSegmentGrowZoneHook::Purge(Size needed)
  261. {
  262.     Size purged = 0;
  263.     for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  264.     {
  265.         Handle h = codeSegment->fCodeSeg;
  266.         if (InlineIsHandleEligible(h) && !IsHandleLocked(h))
  267.         {
  268.             purged += codeSegment->GetSize();
  269.             EmptyAHandle(h);
  270.             if (purged >= needed)
  271.                 break;
  272.         }
  273.     }
  274.     return purged;
  275. } // CCodeSegmentGrowZoneHook::Purge
  276.  
  277. //========================================================================================
  278. // CLASS CCodeSegment
  279. //========================================================================================
  280.  
  281. //----------------------------------------------------------------------------------------
  282. // GetSegResource: 
  283. //----------------------------------------------------------------------------------------
  284. #pragma segment Main
  285.  
  286. Handle CCodeSegment::GetSegResource()
  287. {
  288.     return MAGet1Resource(kCode, fSegNum);
  289. } // GetSegResource 
  290.  
  291. //----------------------------------------------------------------------------------------
  292. // IsSegmentLoaded: Returns whether the segment 
  293. //                        is in a loaded (true) or unloaded(false) state.
  294. //
  295. // IsSegmentLoaded must be in Main segment because we call this in order to make the 
  296. // resident segment resident.
  297. //----------------------------------------------------------------------------------------
  298. #pragma segment Main
  299.  
  300. Boolean CCodeSegment::IsSegmentLoaded()
  301. {
  302.     Boolean returnVal = FALSE;
  303.  
  304.     static const short kLoaded = 0x4EF9;        // if loaded then a JMP instruction
  305.  
  306.     if (fSegNum != 0) // don't care about special zero segment
  307.     {
  308. #if defined(__MWERKS__)
  309.         if (fSegNum < 2)
  310.             returnVal = TRUE;
  311.         else
  312. #endif             
  313.         if (*fCodeSeg && (*((const short *)((long)this->GetFirstFunctionPointer())) == kLoaded))
  314.             returnVal = TRUE;
  315.     }
  316.  
  317.     return returnVal;
  318. } // IsSegmentLoaded 
  319.  
  320. //----------------------------------------------------------------------------------------
  321. // GetSize: 
  322. //----------------------------------------------------------------------------------------
  323. #pragma segment Main
  324.  
  325. Size CCodeSegment::GetSize()
  326. {
  327.     if (fSegSize == -1)
  328.     {
  329.         if (fCodeSeg && !InlineIsHandlePurged(fCodeSeg))
  330.             fSegSize = InlineGetHandleSize(fCodeSeg);
  331.         else
  332.             fSegSize = GetResourceSizeOnDisk(fCodeSeg);
  333.     }
  334.     return fSegSize;
  335. } // GetSize 
  336.  
  337. //----------------------------------------------------------------------------------------
  338. // CCodeSegment::LoadMacAppSegment: 
  339. //----------------------------------------------------------------------------------------
  340. #pragma segment Main
  341. // must be in Main segment 
  342.  
  343. void CCodeSegment::LoadMacAppSegment()
  344. {
  345.     if (!this->PreloadSegmentResource())
  346.     {
  347. #if qDebug
  348.         DebugStr((StringPtr)"\pFailure in CCodeSegment::LoadMacAppSegment");
  349. #endif
  350.         Failure(memFullErr, 0);
  351.     }
  352.  
  353.     fSegLoaderLoaded = TRUE;
  354.  
  355. #if qDebug
  356.     if (gSegReport)
  357.     {
  358.         short id;
  359.         ResType kind;
  360.         CStr255 segName;
  361.         MAName s;
  362.  
  363.         GetResInfo(fCodeSeg, &id, &kind, segName);
  364.         fprintf(stderr, "  *** Segment Loaded: %d %s\n", fSegNum, (const char*)segName);
  365.     }
  366. #endif
  367. } // LoadMacAppSegment 
  368.  
  369. //----------------------------------------------------------------------------------------
  370. // PreloadSegmentResource: 
  371. //----------------------------------------------------------------------------------------
  372. #pragma segment Main
  373. // must be in Main segment 
  374.  
  375. pascal Boolean PreloadSegmentResource(short segNum)
  376. {
  377.     return GetCodeSegmentFromID(segNum)->PreloadSegmentResource();
  378. }
  379.  
  380. //----------------------------------------------------------------------------------------
  381. // PreloadSegmentResource: 
  382. //----------------------------------------------------------------------------------------
  383. #pragma segment Main
  384. // must be in Main segment 
  385.  
  386. Boolean CCodeSegment::PreloadSegmentResource()
  387. {
  388.     Boolean returnVal = FALSE;
  389.  
  390.     if (fSegLoaderLoaded)
  391.         returnVal = TRUE;
  392.     else
  393.     {
  394.         short oldResFile = MAUseResFile(gCodeRefNum);
  395.     
  396.         Boolean saveResLoad = MASetResLoad(TRUE);                            // yes, we really *do* want it.
  397.  
  398.         Boolean priorTemp = TemporaryAllocation(TRUE);// Code segments are temp
  399.         Handle seg = MAGet1Resource(kCode, fSegNum);
  400.         TemporaryAllocation(priorTemp);
  401.  
  402.         SetResLoad(saveResLoad);
  403.     
  404.         MAUseResFile(oldResFile);
  405.     
  406.         if (seg)
  407.         {
  408.             HNoPurge(seg);
  409. #if !defined(__MWERKS__)
  410.             if (!IsHandleLocked(seg))                // not yet locked 
  411.                 LockHandleHigh(seg);
  412. #endif
  413.             returnVal = TRUE;
  414.         }
  415.     }
  416.  
  417.  
  418. #if qDebug
  419.     fEverLoaded = TRUE;
  420.  
  421.     Size total = 0;
  422.     {
  423.         for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  424.             if (codeSegment->fSegLoaderLoaded)
  425.                     total += codeSegment->GetSize() + kHeapOverhead;
  426.     }
  427.     
  428.     if (total > gHighWater)
  429.     {
  430.         gHighWater = total;
  431.  
  432.         for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  433.             codeSegment->fHighWater = codeSegment->fSegLoaderLoaded;
  434.     }
  435. #endif
  436.  
  437.     return returnVal;
  438. } // PreloadSegmentResource 
  439.  
  440. //----------------------------------------------------------------------------------------
  441. // SetResidentSegment: 
  442. //----------------------------------------------------------------------------------------
  443. #pragma segment Main
  444.  
  445. // must be in Main segment 
  446.  
  447. void CCodeSegment::SetResidentSegment(Boolean makeResident)
  448. {
  449.     if (makeResident)
  450.     {
  451.         fResidentSeg = TRUE;
  452.         if (!this->IsSegmentLoaded())
  453.         {
  454.             // Load the segment resource, no need to call LoadSeg now
  455. #if defined(__MWERKS__)
  456.             if (PreloadSegment(fSegNum))
  457. #else
  458.             if (this->PreloadSegmentResource())
  459. #endif
  460.                 fSegLoaderLoaded = TRUE;
  461.             else
  462.                 Failure(memFullErr, 0);
  463.         }
  464.     }
  465.     else
  466.         fResidentSeg = FALSE;
  467. } // SetResidentSegment 
  468.  
  469. //----------------------------------------------------------------------------------------
  470. // IsModelFar: 
  471. //----------------------------------------------------------------------------------------
  472. #ifdef __MWERKS__
  473. const short kJTSkipOver = 4;                    //for large model, CW looks at the 2nd long in the resource 
  474. #else
  475. const short kJTSkipOver = 2;                    // size of jmp (or loadseg) instruction
  476.                                                 // that must be skipped in the JT Entry in
  477.                                                 // order to get to the target address
  478. #endif
  479.  
  480. struct ModelFarCodeHeader
  481. {
  482.     short field1;
  483.     short field2;
  484.     long A5OffsetOf16BitEntries;
  485.     long numOf16BitEntries;
  486.     long A5OffsetOf32BitEntries;
  487.     long numOf32BitEntries;
  488.     char otherEvenMorePrivateStuff;            // You didn't think I would reveal any more
  489.                                             // than I had to did you?
  490. };
  491.  
  492. typedef ModelFarCodeHeader ** ModelFarCodeHeaderHandle;
  493.  
  494. #pragma segment Main
  495.  
  496. Boolean CCodeSegment::IsModelFar()
  497. {
  498. #ifdef __MWERKS__
  499.     return FALSE;
  500. #else
  501.     static const short kModelFarFlag = 0xFFFF;
  502.     return fCodeSeg && (*(ModelFarCodeHeaderHandle)fCodeSeg)->field1 == kModelFarFlag;
  503. #endif // __MWERKS__
  504. }                                                // IsModelFar
  505.  
  506. //----------------------------------------------------------------------------------------
  507. // IsModelCFM: 
  508. //----------------------------------------------------------------------------------------
  509. #pragma segment Main
  510.  
  511. #if qModelCFM
  512.  
  513. Boolean CCodeSegment::IsModelCFM()
  514. {
  515.     static const short kModelCFMFlag = 0xFFFD;
  516.     return fCodeSeg && (*(ModelFarCodeHeaderHandle)fCodeSeg)->field1 == kModelCFMFlag;
  517. }                                                // IsModelCFM
  518.  
  519. #endif // qModelCFM
  520.  
  521. //----------------------------------------------------------------------------------------
  522. // GetFirstFunctionPointer: 
  523. //----------------------------------------------------------------------------------------
  524. #pragma segment Main
  525.  
  526. Ptr CCodeSegment::GetFirstFunctionPointer()
  527. {
  528.     Ptr unloadPtr;
  529.  
  530.     long* jmpTablePtr = (long*)(GetA5() + LMGetCurJTOffset());
  531.  
  532. #if qModelCFM
  533.     if (this->IsModelCFM())
  534.     {
  535.         unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf16BitEntries + kJTSkipOver);
  536.     }
  537. #else
  538.     if (this->IsModelFar())
  539.     {
  540.         if ((*((ModelFarCodeHeaderHandle)fCodeSeg))->numOf16BitEntries)
  541.             unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf16BitEntries + kJTSkipOver);
  542.         else    // Has to be the other since we wouldn't even have a segment otherwise
  543.             unloadPtr = (Ptr)(jmpTablePtr + (*((ModelFarCodeHeaderHandle)fCodeSeg))->A5OffsetOf32BitEntries + kJTSkipOver);
  544.     }
  545. #endif // qModelCFM
  546.     else
  547.     {
  548.         // Model near
  549. #ifdef __MWERKS__
  550.         unloadPtr = (Ptr)((*(long*)((*fCodeSeg) + kJTSkipOver)) + (long)GetA5());
  551. #else
  552.         unloadPtr = (Ptr)(jmpTablePtr + **((IntegerHandle)fCodeSeg) + kJTSkipOver);
  553. #endif
  554.     }
  555.  
  556.     return unloadPtr;
  557. }
  558.  
  559. //----------------------------------------------------------------------------------------
  560. // GetFirstFunctionPointer: 
  561. //----------------------------------------------------------------------------------------
  562. #pragma segment Main
  563.  
  564. void CCodeSegment::Unload()
  565. {
  566.     UnloadSeg(this->GetFirstFunctionPointer());
  567.     HNoPurge(this->fCodeSeg); // UnloadSeg made it purgeable
  568.  
  569.     fSegLoaderLoaded = FALSE;
  570. }
  571.  
  572. //----------------------------------------------------------------------------------------
  573. // ContainsAddress: 
  574. //----------------------------------------------------------------------------------------
  575. #pragma segment Main
  576.  
  577. Boolean CCodeSegment::ContainsAddress(void* address)
  578. {
  579.     short returnVal = FALSE;
  580.  
  581.     if (fCodeSeg && !InlineIsHandlePurged(fCodeSeg))    // it's in memory 
  582.     {
  583.         long segStart = StripLong(*fCodeSeg);// get segment start 
  584.         if (((long)address >= segStart) && ((long)address < segStart + this->GetSize()))
  585.             returnVal = TRUE;
  586.     }
  587.  
  588.     return returnVal;                            // default return
  589. }
  590.  
  591. //========================================================================================
  592. // GLOBAL Procedures
  593. //========================================================================================
  594.  
  595. //----------------------------------------------------------------------------------------
  596. // GetCodeSegmentFromName: 
  597. //----------------------------------------------------------------------------------------
  598. #pragma segment Main
  599.  
  600. CCodeSegment* GetCodeSegmentFromName(const CStr255& name)
  601. {
  602.     CCodeSegment* returnVal = NULL;
  603.  
  604.     Boolean oldResLoad = MASetResLoad(FALSE);
  605.     Handle seg = MAGet1NamedResource(kCode, name);
  606.     if (seg)
  607.     {
  608.         short rsrcID;
  609.         ResType rsrcType;
  610.         CStr255 rsrcName;
  611.         GetResInfo(seg, &rsrcID, &rsrcType, rsrcName);
  612.  
  613.         returnVal = GetCodeSegmentFromID(rsrcID);
  614.     }
  615.     SetResLoad(oldResLoad);
  616.     
  617.     return returnVal;
  618. }
  619.  
  620. //----------------------------------------------------------------------------------------
  621. // AddSegSizes: 
  622. //----------------------------------------------------------------------------------------
  623. #pragma segment MAMiniInit
  624.  
  625. Size AddSegSizes(Handle nameList)
  626. {
  627.     SignedByte savedState = LockHandle(nameList);
  628.  
  629.     Ptr nameListPtr = *nameList;
  630.     short numStrings = *((short*)nameListPtr);
  631.     nameListPtr += sizeof(short);
  632.  
  633.     register long total = 0;
  634.  
  635.     for (; numStrings; --numStrings, nameListPtr += *nameListPtr + 1)
  636.     {
  637.         // count once and only once
  638.         CCodeSegment* codeSegment = GetCodeSegmentFromName((CStr255&)*nameListPtr);
  639.         if (codeSegment && !codeSegment->fInTemporaryReserve)
  640.         {
  641.             codeSegment->fInTemporaryReserve = TRUE;
  642.             total += codeSegment->GetSize() + kHeapOverhead;
  643.         }
  644.     }
  645.  
  646.     HSetState(nameList, savedState);
  647.  
  648.     return total;
  649. } // AddSegSizes 
  650.  
  651. //----------------------------------------------------------------------------------------
  652. // DoInitUSegments: Called from InitUSegments so that InitUSegments can be in the main segment
  653. // and this code can be in another (unloadable) segment.
  654. //----------------------------------------------------------------------------------------
  655. #pragma segment MAMiniInit
  656.  
  657. void DoInitUSegments(Size& temporaryReserve)
  658. {
  659.     //###########################################
  660.     // No resource loading 
  661.  
  662.     Boolean oldResLoad = MASetResLoad(FALSE);
  663.  
  664.     // Figure the highest segment number 
  665.     // some development systems may not have contiguous numbering of CODE segments. try to
  666.     // be polite about handling it
  667.     // we only have an index find the real resource ID and keep track of the highest one
  668.  
  669.     short lastRsrc = MACount1Resources(kCode);
  670.     for (short rsrcIndex = 1; rsrcIndex <= lastRsrc; ++rsrcIndex)
  671.     {
  672.         Handle seg = MAGet1IndResource(kCode, rsrcIndex);
  673.  
  674.         if (seg)
  675.         {
  676.             short rsrcID;
  677.             ResType rsrcType;
  678.             CStr255 rsrcName;
  679.             GetResInfo(seg, &rsrcID, &rsrcType, rsrcName);
  680.             pMaxSegNum = (short)Max(rsrcID, pMaxSegNum);
  681.         }
  682.     }
  683.  
  684.     SetResLoad(oldResLoad);                        // in case of failure 
  685.  
  686.     // Allocate the master segment list.
  687.     gCodeSegs = (CCodeSegment*)NewPtr((pMaxSegNum + 1) * sizeof(CCodeSegment));
  688.     FailNIL(gCodeSegs);
  689.  
  690.     oldResLoad = MASetResLoad(FALSE);
  691.  
  692.     // Segments and their sizes and actual loaded state (helps catch preloads)
  693.  
  694.     CCodeSegment* prevSegPtr = NULL;
  695.     short i = 0;
  696.     for (CCodeSegment* codeSegment = GetCodeSegmentFromID(i); i <= pMaxSegNum; codeSegment = GetCodeSegmentFromID(++i))
  697.     {
  698.         codeSegment->fSegNum = i;
  699.         codeSegment->fResidentSeg = FALSE;
  700.         codeSegment->fInTemporaryReserve = FALSE;
  701.         codeSegment->fCodeSeg = codeSegment->GetSegResource();
  702.         codeSegment->fSegLoaderLoaded = FALSE;
  703.         codeSegment->fSegSize = -1;
  704.  
  705.         codeSegment->fCanUnload = !(GetResAttrs(codeSegment->fCodeSeg) & resPreload); // don't unload the preloads
  706.  
  707.         if (codeSegment->fCodeSeg)
  708.         {
  709.             codeSegment->fSegLoaderLoaded = codeSegment->IsSegmentLoaded();
  710.             if (!InlineIsHandlePurged(codeSegment->fCodeSeg))
  711.                 HNoPurge(codeSegment->fCodeSeg);
  712.         }
  713.         
  714.         codeSegment->fNextCodeSegment = NULL;
  715.  
  716.         if (prevSegPtr)
  717.             prevSegPtr->fNextCodeSegment = codeSegment;
  718.  
  719. #if qDebug
  720.             codeSegment->fHighWater = FALSE;
  721.             codeSegment->fEverLoaded = codeSegment->fSegLoaderLoaded;
  722. #endif        
  723.  
  724.  
  725.         prevSegPtr = codeSegment;
  726.     }
  727.  
  728.     SetResLoad(oldResLoad);
  729.     //###########################################
  730. #if !(qModelCFM && defined(__MWERKS__))
  731. //••• SRF #if is a hack to get it running
  732.     GetUnloadedCodeSegment((ProcPtr)InitUMemory)->fResidentSeg = TRUE;// Main is always resident 
  733.  
  734.     GetUnloadedCodeSegment((ProcPtr)UnloadAllSegments)->fResidentSeg = TRUE;// Utilities are always resident 
  735. #endif
  736.  
  737. #if qModelFarCode && !defined(__MWERKS__)
  738.     {
  739.         CCodeSegment* codeSegment = GetCodeSegmentFromName(CStr255("32-bit bootstrap"));
  740.         if (codeSegment)
  741.             codeSegment->fResidentSeg = TRUE;
  742.     }
  743. #endif
  744.  
  745.     // Compute memory slop needed to respect the segments in the temp reserve
  746.     short rsrcCnt = CountResources('seg!');
  747.     for (short segRsrcIndex = 1; segRsrcIndex <= rsrcCnt; ++segRsrcIndex)
  748.     {
  749.         Handle h = GetIndResource('seg!', segRsrcIndex);
  750.         temporaryReserve += AddSegSizes(h);
  751.         ReleaseResource(h);
  752.     }
  753.  
  754.     //
  755.     // Catch the preloads added by the IDE that may not be included in the seg! resource above
  756.     //
  757.     {
  758.         for (CCodeSegment * codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  759.         {
  760.             if (!codeSegment->fCanUnload && !codeSegment->fInTemporaryReserve)
  761.                 temporaryReserve += codeSegment->GetSize() + kHeapOverhead;
  762.         }
  763.     }
  764.  
  765. } // DoInitUSegments 
  766.  
  767. //----------------------------------------------------------------------------------------
  768. // GetLoadedCodeSegment: 
  769. //----------------------------------------------------------------------------------------
  770. #pragma segment Main
  771.  
  772. // Shouldn't be unloaded 
  773.  
  774. CCodeSegment* GetLoadedCodeSegment(void* pc)
  775. {
  776.     CCodeSegment* returnVal = NULL;
  777.  
  778.     for (CCodeSegment* codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  779.     {
  780.         if (codeSegment->ContainsAddress(pc))
  781.         {
  782.             returnVal = codeSegment;
  783.             break;
  784.         }
  785.     }
  786.  
  787.     return returnVal;                            // default return
  788. } // GetLoadedCodeSegment 
  789.  
  790. //----------------------------------------------------------------------------------------
  791. // GetUnloadedCodeSegment: Gets CodeSegment from a Jump table address.
  792. //
  793. // Must be in Main segment because we call this in order to make the resident segment
  794. // resident.
  795. //----------------------------------------------------------------------------------------
  796. #pragma segment Main
  797.  
  798. CCodeSegment* GetUnloadedCodeSegment(ProcPtr aProc)
  799. {
  800.     const short kJump = 0x4EF9;            // if loaded then a JMP instruction
  801.     const short kMove = 0x3F3C;            // if unloaded then a Move instruction (seg# onto stack)
  802.  
  803.     // Check for load and unloaded state, otherwise we are not pointing
  804.     // at a valid jump table entry. 
  805.     
  806. #if defined(__MWERKS__)
  807.  
  808.     // Function addresses taken segment 1 with Smart and Large model are not jump table addresses.
  809.     
  810.     static Size code1Start = 0;
  811.     static Size code1End = 0;
  812.     Size target = (Size)aProc;
  813.     
  814.     if (!code1Start) // the following is done once to get the "dimensions" of the first segment
  815.     {
  816.         Handle code1 = MAGet1Resource(kCode, 1); 
  817.         code1Start = (Size)StripAddress(*(Ptr*)code1);
  818.         code1End = code1Start + InlineGetHandleSize(code1);
  819.     }
  820.     if ((target > code1Start) && (target < code1End))
  821.         return GetCodeSegmentFromID(1);
  822.  
  823.     // Try again on the off chance that you might be using Small model. 
  824.     // Small model doesn't use a jump table which has the segment number for
  825.     // references to segment 1. 
  826.     // The first 2 bytes are kJump and the next 4 bytes are the absolute address. 
  827.  
  828.     if (*(short*)target == kJump)
  829.     {
  830.         target = *(Size*)(target + 2);
  831.         if ((target > code1Start) && (target < code1End))
  832.             return GetCodeSegmentFromID(1);        
  833.     }
  834.     
  835.     // Well we aren't in segment 1 so we are guaranteed a real jump table entry.    
  836.     
  837.     if (*((const short *)aProc) == kJump || *((const short *)aProc) == (short)_LoadSeg)
  838.         return GetCodeSegmentFromID(*((const short *)((const char *) aProc + 6)));
  839.  
  840. #if qDebug
  841.     ProgramBreak("GetUnloadedCodeSegment was not passed a valid function address.");        
  842. #endif
  843.     return NULL;
  844.  
  845. #else
  846.  
  847.     // Non-Metrowerks
  848.     
  849. #if qModelFarCode || qModelCFM
  850.  
  851.     // In a model far jump table entry the first two bytes are the segment number
  852.     // whether the segment is loaded or not.
  853.     
  854.     if (*((const short *)aProc) == kJump || *((const short *)aProc) == (short)_LoadSeg)
  855.         return GetCodeSegmentFromID(*((const short *)((const char *)aProc - 2)));
  856.  
  857. #else
  858.  
  859.     // Classic 68K runtime
  860.     
  861.     if (*((const short *)aProc) == kJump)        // loaded segment
  862.         return GetCodeSegmentFromID(*((const short *)((const char *) aProc - 2)));
  863.     else if (*((const short *)aProc) == kMove)    // unloaded segment
  864.         return GetCodeSegmentFromID(*((const short *)((const char *) aProc + 2)));
  865.  
  866. #endif
  867.  
  868.     else
  869.     {
  870.         // routine that computed &proc was in same segment as the proc
  871. #if qDebug
  872.         ProgramBreak("GetUnloadedCodeSegment was not passed an jump table address");
  873. #endif
  874.         return NULL;
  875.     }
  876.  
  877. #endif // defined(__MWERKS__)
  878.  
  879. } // GetUnloadedCodeSegment 
  880.  
  881. //----------------------------------------------------------------------------------------
  882. // PreloadHandler: 
  883. //----------------------------------------------------------------------------------------
  884. #if qUseRTLib
  885. #pragma segment Main
  886.  
  887. pascal short PreloadHandler(RTState* state)
  888. {
  889.     short returnVal = 0;
  890.  
  891.     LoadMacAppSegment(state->fSegNo);
  892.  
  893.     if (oldPreLoadHandler)
  894.         returnVal = ((HandlerType)oldPreLoadHandler)(state);
  895.  
  896.     return returnVal;
  897. } // PreloadHandler 
  898. #endif
  899.  
  900. //----------------------------------------------------------------------------------------
  901. // PostLoadMacAppSegment: 
  902. //----------------------------------------------------------------------------------------
  903. #pragma segment Main
  904.  
  905. // must be in Main segment 
  906. // NOTE: this routine requires the pascal keyword because it is called from assembler
  907. // code that assumes pascal parameter passing conventions.
  908.  
  909. pascal void PostLoadMacAppSegment()
  910. {
  911.     long A5RegisterOnEntry = SetCurrentA5();    // can be called from trap patches
  912.     
  913.     if (pLoadSegCalledFromOwnApp)
  914.         MAUseResFile(pOldResFile);
  915.     
  916.     SetA5(A5RegisterOnEntry);
  917. } // PostLoadMacAppSegment 
  918.  
  919. //----------------------------------------------------------------------------------------
  920. // PostloadHandler: 
  921. //----------------------------------------------------------------------------------------
  922. #if qUseRTLib
  923. #pragma segment Main
  924.  
  925. pascal short PostloadHandler(RTState* state)
  926.  
  927. {
  928.     short returnVal = 0;
  929.  
  930.     PostLoadMacAppSegment();
  931.     if (oldPostLoadHandler)
  932.         returnVal = ((HandlerType)oldPostLoadHandler)(state);
  933.  
  934.     return returnVal;
  935. } // PostloadHandler 
  936. #endif
  937.  
  938. //----------------------------------------------------------------------------------------
  939. // InitUSegments: 
  940. //----------------------------------------------------------------------------------------
  941. #pragma segment Main
  942. // Must be in main segment and called from main segment
  943.  
  944. void InitUSegments()
  945. {
  946.     // Install our memory hook for the grow zone proc
  947.     // (Maybe the should be installed later, but this is closer to
  948.     //  the old way TotalTempSize worked.)
  949.     gCodeSegmentGrowZoneHook.InsertFirst();
  950.     
  951.     long temporaryReserve;
  952.     long lowSpaceRes;
  953.     
  954.     GetReserveSize(temporaryReserve, lowSpaceRes);
  955.  
  956.     DoInitUSegments(temporaryReserve);
  957.  
  958.     // Set up the LoadSeg patch 
  959.  
  960. #if qUseRTLib
  961.     // Use the cool new RTLib so graciously
  962.     // provided by Landon and Sandra
  963.     RTPB anRTPB;
  964.  
  965.     // Install the preload handler
  966.     anRTPB.fOperation = kRTSetPreLoad;
  967.     anRTPB.fRTParam.fSegLoadParam.fUserHdlr = (SegLoadHdlrPtr)StripLong(PreloadHandler);
  968.     if (Runtime(&anRTPB) != noErr)
  969.         Failure(minErr, 0);
  970.     oldPreLoadHandler = anRTPB.fRTParam.fSegLoadParam.fOldUserHdlr;
  971.  
  972.     // Install the postload handler
  973.     anRTPB.fOperation = kRTSetPostLoad;
  974.     anRTPB.fRTParam.fSegLoadParam.fUserHdlr = (SegLoadHdlrPtr)StripLong(PostloadHandler);
  975.     if (Runtime(&anRTPB) != noErr)
  976.         Failure(minErr, 0);
  977.     oldPostLoadHandler = anRTPB.fRTParam.fSegLoadParam.fOldUserHdlr;
  978. #if !qModelCFM
  979.     pSegLoadPatch.LookupOldTrapAddress(_LoadSeg);
  980. #endif
  981. #else
  982. #if !qModelCFM
  983.     FailOSErr(pSegLoadPatch.PatchTrap(_LoadSeg, ALoadMacAppSeg));
  984. #endif
  985. #endif
  986.  
  987.     UnloadAllSegments(TRUE);                    // get init segment(s) out of middle of
  988.                                                 // heap, so SetReserveSize has maximum
  989.                                                 // space to work with
  990.  
  991.     LoadResidentSegments();
  992.  
  993.     SetReserveSize(temporaryReserve, lowSpaceRes);
  994.     
  995.     FailSpaceIsLow();                            // couldn't get temorary reserve. Can't continue
  996. } // InitUSegments 
  997.  
  998.  
  999. //----------------------------------------------------------------------------------------
  1000. // LoadMacAppSegment: 
  1001. //----------------------------------------------------------------------------------------
  1002. #pragma segment Main
  1003. // must be in Main segment 
  1004.  
  1005. pascal UniversalProcPtr LoadMacAppSegment(short segnum)
  1006. {
  1007.     long A5RegisterOnEntry = SetCurrentA5();    // can be called from trap patches
  1008.  
  1009.     UniversalProcPtr loadMacAppSegment = NULL;
  1010. #if !qModelCFM
  1011.     loadMacAppSegment = pSegLoadPatch.GetOldTrapAddr();// Where to go next 
  1012. #endif
  1013.  
  1014.     if (GetA5() != A5RegisterOnEntry)
  1015.     {
  1016.         // not called from our application… don't do patch behaviour. Thank you McSink! 
  1017.         pLoadSegCalledFromOwnApp = FALSE;
  1018.         SetA5(A5RegisterOnEntry);
  1019.     }
  1020.     else
  1021.     {
  1022.         pLoadSegCalledFromOwnApp = TRUE;
  1023.         pOldResFile = MAUseResFile(gCodeRefNum);
  1024.         // Must set a global because we return
  1025.         // from this function and then forward to
  1026.         // the actual segment loader which should
  1027.         // also be pointing to the _now_ correct
  1028.         // resfile. When we get called back again
  1029.         // in PostLoadMacAppSegment we will
  1030.         // restore the old resFile as the current
  1031.         // resFile. Sorry about the global.
  1032.  
  1033.         GetCodeSegmentFromID(segnum)->LoadMacAppSegment();
  1034.     }
  1035.  
  1036.     return loadMacAppSegment;
  1037. } // LoadMacAppSegment 
  1038.  
  1039. //----------------------------------------------------------------------------------------
  1040. // LoadResidentSegments: 
  1041. //----------------------------------------------------------------------------------------
  1042. #pragma segment Main
  1043. // Must be in Main segment 
  1044.  
  1045. void LoadResidentSegments()
  1046. {
  1047.     short rsrcCnt = CountResources('res!');
  1048.     for (short resIndex = 1; resIndex <= rsrcCnt; ++resIndex)
  1049.     {
  1050.         Handle nameList = GetIndResource('res!', resIndex);
  1051.         SignedByte savedState = LockHandle(nameList);
  1052.  
  1053.         Ptr nameListPtr = *nameList;
  1054.         short numStrings = *((short*)nameListPtr);
  1055.         nameListPtr += sizeof(short);
  1056.     
  1057.         for (; numStrings; --numStrings, nameListPtr += *nameListPtr + 1)
  1058.         {
  1059.             CCodeSegment* codeSegment = GetCodeSegmentFromName((CStr255&)*nameListPtr);
  1060.             if (codeSegment)
  1061.                 codeSegment->SetResidentSegment(TRUE);
  1062.         }
  1063.  
  1064.         HSetState(nameList, savedState);
  1065.         ReleaseResource(nameList);
  1066.     }
  1067. } // LoadResidentSegments 
  1068.  
  1069. #if qDebug
  1070. //----------------------------------------------------------------------------------------
  1071. // CheckCallChain: 
  1072. //----------------------------------------------------------------------------------------
  1073. #pragma segment Main
  1074. // must be in Main segment 
  1075.  
  1076. void CheckCallChain(const CStackFrame& frame,
  1077.                     void* /* yourDataPtr */ )
  1078. {
  1079.     void* pc = frame.GetReturnAddress();
  1080.  
  1081.     CCodeSegment* codeSegment = GetLoadedCodeSegment(pc);
  1082.     if (codeSegment && codeSegment->fSegLoaderLoaded && codeSegment->fCanUnload && !codeSegment->fResidentSeg)
  1083.     {
  1084.         fprintf(stderr, "Segment#: %d\n", codeSegment->fSegNum);
  1085.         ProgramBreak("you don't want to auto-unload a resident or preleoaded (!fCanUnload) segment!");
  1086.     }
  1087. } // CheckCallChain 
  1088.  
  1089. #endif
  1090.  
  1091. //----------------------------------------------------------------------------------------
  1092. // UnloadAllSegments: 
  1093. //----------------------------------------------------------------------------------------
  1094. #pragma segment MAMemoryRes
  1095.  
  1096. void UnloadAllSegments(Boolean andPurge)
  1097. {
  1098. #if qModelCFM && defined(__MWERKS__)
  1099. //••• SRF hack to get it running
  1100.     return;
  1101. #endif
  1102.  
  1103.     CheckRsrcUsage();
  1104.  
  1105.     if (gUnloadAllSegs)
  1106.     {
  1107. #if qDebug
  1108.         CStackFrame stackFrame((void*)GetCurStackFramePtr());
  1109.         EachFrameDo(stackFrame, CheckCallChain, NULL);
  1110. #endif
  1111.  
  1112.         short oldResFile = MAUseResFile(gCodeRefNum);
  1113.  
  1114.         for (CCodeSegment* codeSegment = gCodeSegs; codeSegment; codeSegment = codeSegment->fNextCodeSegment)
  1115.         {
  1116.             if (codeSegment->fSegLoaderLoaded && codeSegment->fCanUnload && !codeSegment->fResidentSeg)
  1117.             {
  1118.                 Handle seg = codeSegment->fCodeSeg;
  1119.                 if (seg && !InlineIsHandlePurged(seg) && codeSegment->fCanUnload)
  1120.                 {
  1121.                     codeSegment->Unload();
  1122.  
  1123.                     if (andPurge)
  1124.                         EmptyHandle(seg);
  1125. //                    else
  1126. //                        HNoPurge(seg);
  1127.                 }
  1128.             }
  1129.         }
  1130.         MAUseResFile(oldResFile);
  1131.  
  1132.         if (gSegReport)
  1133.             ProgramReport("  *** Just unloaded all segments ***", gMemMgtBreak);
  1134.     }
  1135. } // UnloadAllSegments 
  1136.  
  1137. #endif // qSegments
  1138.  
  1139. //----------------------------------------------------------------------------------------
  1140. // End of USegments.cp
  1141.  
  1142. #pragma segment Inline
  1143.